define(["require", "exports", "vscode-jsonrpc/is", "vscode-jsonrpc/messages", "vscode-jsonrpc/events", "vscode-jsonrpc/cancellation"], function (require, exports, Is, messages_1, events_1, cancellation_1) {
    /* --------------------------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * Licensed under the MIT License. See License.txt in the project root for license information.
     * ------------------------------------------------------------------------------------------ */
    /// <reference path="./thenable.ts" />
    'use strict';
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.RequestType = messages_1.RequestType;
    exports.RequestType0 = messages_1.RequestType0;
    exports.RequestType1 = messages_1.RequestType1;
    exports.RequestType2 = messages_1.RequestType2;
    exports.RequestType3 = messages_1.RequestType3;
    exports.RequestType4 = messages_1.RequestType4;
    exports.RequestType5 = messages_1.RequestType5;
    exports.RequestType6 = messages_1.RequestType6;
    exports.RequestType7 = messages_1.RequestType7;
    exports.RequestType8 = messages_1.RequestType8;
    exports.RequestType9 = messages_1.RequestType9;
    exports.ResponseError = messages_1.ResponseError;
    exports.ErrorCodes = messages_1.ErrorCodes;
    exports.NotificationType = messages_1.NotificationType;
    exports.NotificationType0 = messages_1.NotificationType0;
    exports.NotificationType1 = messages_1.NotificationType1;
    exports.NotificationType2 = messages_1.NotificationType2;
    exports.NotificationType3 = messages_1.NotificationType3;
    exports.NotificationType4 = messages_1.NotificationType4;
    exports.NotificationType5 = messages_1.NotificationType5;
    exports.NotificationType6 = messages_1.NotificationType6;
    exports.NotificationType7 = messages_1.NotificationType7;
    exports.NotificationType8 = messages_1.NotificationType8;
    exports.NotificationType9 = messages_1.NotificationType9;
    exports.Disposable = events_1.Disposable;
    exports.Event = events_1.Event;
    exports.Emitter = events_1.Emitter;
    exports.CancellationTokenSource = cancellation_1.CancellationTokenSource;
    exports.CancellationToken = cancellation_1.CancellationToken;
    exports.NullLogger = Object.freeze({
        error: () => { },
        warn: () => { },
        info: () => { },
        log: () => { }
    });
    var Trace;
    (function (Trace) {
        Trace[Trace["Off"] = 0] = "Off";
        Trace[Trace["Messages"] = 1] = "Messages";
        Trace[Trace["Verbose"] = 2] = "Verbose";
    })(Trace = exports.Trace || (exports.Trace = {}));
    (function (Trace) {
        function fromString(value) {
            value = value.toLowerCase();
            switch (value) {
                case 'off':
                    return Trace.Off;
                case 'messages':
                    return Trace.Messages;
                case 'verbose':
                    return Trace.Verbose;
                default:
                    return Trace.Off;
            }
        }
        Trace.fromString = fromString;
        function toString(value) {
            switch (value) {
                case Trace.Off:
                    return 'off';
                case Trace.Messages:
                    return 'messages';
                case Trace.Verbose:
                    return 'verbose';
                default:
                    return 'off';
            }
        }
        Trace.toString = toString;
    })(Trace = exports.Trace || (exports.Trace = {}));
    var SetTraceNotification;
    (function (SetTraceNotification) {
        SetTraceNotification.type = new messages_1.NotificationType('$/setTraceNotification');
    })(SetTraceNotification = exports.SetTraceNotification || (exports.SetTraceNotification = {}));
    var LogTraceNotification;
    (function (LogTraceNotification) {
        LogTraceNotification.type = new messages_1.NotificationType('$/logTraceNotification');
    })(LogTraceNotification = exports.LogTraceNotification || (exports.LogTraceNotification = {}));
    var ConnectionErrors;
    (function (ConnectionErrors) {
        /**
         * The connection is closed.
         */
        ConnectionErrors[ConnectionErrors["Closed"] = 1] = "Closed";
        /**
         * The connection got disposed.
         */
        ConnectionErrors[ConnectionErrors["Disposed"] = 2] = "Disposed";
        /**
         * The connection is already in listening mode.
         */
        ConnectionErrors[ConnectionErrors["AlreadyListening"] = 3] = "AlreadyListening";
    })(ConnectionErrors = exports.ConnectionErrors || (exports.ConnectionErrors = {}));
    class ConnectionError extends Error {
        constructor(code, message) {
            super(message);
            this.code = code;
            Object.setPrototypeOf(this, ConnectionError.prototype);
        }
    }
    exports.ConnectionError = ConnectionError;
    var ConnectionStrategy;
    (function (ConnectionStrategy) {
        function is(value) {
            let candidate = value;
            return candidate && Is.func(candidate.cancelUndispatched);
        }
        ConnectionStrategy.is = is;
    })(ConnectionStrategy = exports.ConnectionStrategy || (exports.ConnectionStrategy = {}));
});
// interface ResponsePromise {
// 	method: string;
// 	timerStart: number;
// 	resolve: (response: any) => void;
// 	reject: (error: any) => void
// }
// enum ConnectionState {
// 	New = 1,
// 	Listening = 2,
// 	Closed = 3,
// 	Disposed = 4
// }
// interface RequestHandlerElement {
// 	type: MessageType | undefined;
// 	handler: GenericRequestHandler<any, any>;
// }
// interface NotificationHandlerElement {
// 	type: MessageType | undefined;
// 	handler: GenericNotificationHandler;
// }
// function _createMessageConnection(messageReader: MessageReader, messageWriter: MessageWriter, logger: Logger, strategy?: ConnectionStrategy): MessageConnection {
// 	let sequenceNumber = 0;
// 	let notificationSquenceNumber = 0;
// 	let unknownResponseSquenceNumber = 0;
// 	const version: string = '2.0';
// 	let starRequestHandler: StarRequestHandler | undefined = undefined;
// 	let requestHandlers: { [name: string]: RequestHandlerElement | undefined } = Object.create(null);
// 	let starNotificationHandler: StarNotificationHandler | undefined = undefined;
// 	let notificationHandlers: { [name: string]: NotificationHandlerElement | undefined } = Object.create(null);
// 	let  timer:  NodeJS.Timer | undefined;
// 	let messageQueue: MessageQueue = new LinkedMap<string, Message>();
// 	let responsePromises: { [name: string]: ResponsePromise } = Object.create(null);
// 	let requestTokens: { [id: string]: CancellationTokenSource } = Object.create(null);
// 	let trace: Trace = Trace.Off;
// 	let tracer: Tracer | undefined;
// 	let state: ConnectionState = ConnectionState.New;
// 	let errorEmitter: Emitter<[Error, Message | undefined, number | undefined]> = new Emitter<[Error, Message, number]>();
// 	let closeEmitter: Emitter<void> = new Emitter<void>();
// 	let unhandledNotificationEmitter: Emitter<NotificationMessage> = new Emitter<NotificationMessage>();
// 	let disposeEmitter: Emitter<void> = new Emitter<void>();
// 	function createRequestQueueKey(id: string | number): string {
// 		return 'req-' + id.toString();
// 	}
// 	function createResponseQueueKey(id: string | number | null): string {
// 		if (id === null) {
// 			return 'res-unknown-' + (++unknownResponseSquenceNumber).toString();
// 		} else {
// 			return 'res-' + id.toString();
// 		}
// 	}
// 	function createNotificationQueueKey(): string {
// 		return 'not-' + (++notificationSquenceNumber).toString();
// 	}
// 	function addMessageToQueue(queue: MessageQueue, message: Message): void {
// 		if (isRequestMessage(message)) {
// 			queue.set(createRequestQueueKey(message.id), message);
// 		} else if (isResponseMessage(message)) {
// 			queue.set(createResponseQueueKey(message.id), message);
// 		} else {
// 			queue.set(createNotificationQueueKey(), message);
// 		}
// 	}
// 	function cancelUndispatched(_message: Message): ResponseMessage | undefined {
// 		return undefined;
// 	}
// 	function isListening(): boolean {
// 		return state === ConnectionState.Listening;
// 	}
// 	function isClosed(): boolean {
// 		return state === ConnectionState.Closed;
// 	}
// 	function isDisposed(): boolean {
// 		return state === ConnectionState.Disposed;
// 	}
// 	function closeHandler(): void {
// 		if (state === ConnectionState.New || state === ConnectionState.Listening) {
// 			state = ConnectionState.Closed;
// 			closeEmitter.fire(undefined);
// 		}
// 		// If the connection is disposed don't sent close events.
// 	};
// 	function readErrorHandler(error: Error): void {
// 		errorEmitter.fire([error, undefined, undefined]);
// 	}
// 	function writeErrorHandler(data: [Error, Message, number]): void {
// 		errorEmitter.fire(data);
// 	}
// 	messageReader.onClose(closeHandler);
// 	messageReader.onError(readErrorHandler);
// 	messageWriter.onClose(closeHandler);
// 	messageWriter.onError(writeErrorHandler);
// 	function triggerMessageQueue(): void {
// 		if (timer || messageQueue.size === 0) {
// 			return;
// 		}
// 		timer = setImmediate(() => {
// 			timer = undefined;
// 			processMessageQueue();
// 		});
// 	}
// 	function processMessageQueue(): void {
// 		if (messageQueue.size === 0) {
// 			return;
// 		}
// 		let message = messageQueue.shift()!;
// 		try {
// 			if (isRequestMessage(message)) {
// 				handleRequest(message);
// 			} else if (isNotificationMessage(message)) {
// 				handleNotification(message);
// 			} else if (isResponseMessage(message)) {
// 				handleResponse(message);
// 			} else {
// 				handleInvalidMessage(message);
// 			}
// 		} finally {
// 			triggerMessageQueue();
// 		}
// 	}
// 	let callback: DataCallback = (message) => {
// 		try {
// 			// We have received a cancellation message. Check if the message is still in the queue
// 			// and cancel it if allowed to do so.
// 			if (isNotificationMessage(message) && message.method === CancelNotification.type.method) {
// 				let key = createRequestQueueKey((message.params as CancelParams).id);
// 				let toCancel = messageQueue.get(key);
// 				if (isRequestMessage(toCancel)) {
// 					let response = strategy && strategy.cancelUndispatched ? strategy.cancelUndispatched(toCancel, cancelUndispatched) : cancelUndispatched(toCancel);
// 					if (response && (response.error !== void 0 || response.result !== void 0)) {
// 						messageQueue.delete(key);
// 						response.id = toCancel.id;
// 						traceSendingResponse(response, message.method, Date.now());
// 						messageWriter.write(response);
// 						return;
// 					}
// 				}
// 			}
// 			addMessageToQueue(messageQueue, message);
// 		} finally {
// 			triggerMessageQueue();
// 		}
// 	};
// 	function handleRequest(requestMessage: RequestMessage) {
// 		if (isDisposed()) {
// 			// we return here silently since we fired an event when the
// 			// connection got disposed.
// 			return;
// 		}
// 		function reply(resultOrError: any | ResponseError<any>, method: string, startTime: number): void {
// 			let message: ResponseMessage = {
// 				jsonrpc: version,
// 				id: requestMessage.id
// 			};
// 			if (resultOrError instanceof ResponseError) {
// 				message.error = (<ResponseError<any>>resultOrError).toJson();
// 			} else {
// 				message.result = resultOrError === void 0 ? null : resultOrError;
// 			}
// 			traceSendingResponse(message, method, startTime);
// 			messageWriter.write(message);
// 		}
// 		function replyError(error: ResponseError<any>, method: string, startTime: number) {
// 			let message: ResponseMessage = {
// 				jsonrpc: version,
// 				id: requestMessage.id,
// 				error: error.toJson()
// 			};
// 			traceSendingResponse(message, method, startTime);
// 			messageWriter.write(message);
// 		}
// 		function replySuccess(result: any, method: string, startTime: number) {
// 			// The JSON RPC defines that a response must either have a result or an error
// 			// So we can't treat undefined as a valid response result.
// 			if (result === void 0) {
// 				result = null;
// 			}
// 			let message: ResponseMessage = {
// 				jsonrpc: version,
// 				id: requestMessage.id,
// 				result: result
// 			};
// 			traceSendingResponse(message, method, startTime);
// 			messageWriter.write(message);
// 		}
// 		traceReceivedRequest(requestMessage);
// 		let element = requestHandlers[requestMessage.method];
// 		let type: MessageType | undefined;
// 		let requestHandler: GenericRequestHandler<any, any> | undefined;
// 		if (element) {
// 			type = element.type;
// 			requestHandler = element.handler;
// 		}
// 		let startTime = Date.now();
// 		if (requestHandler || starRequestHandler) {
// 			let cancellationSource = new CancellationTokenSource();
// 			let tokenKey = String(requestMessage.id);
// 			requestTokens[tokenKey] = cancellationSource;
// 			try {
// 				let handlerResult: any;
// 				if (requestMessage.params === void 0 || (type !== void 0 && type.numberOfParams === 0)) {
// 					handlerResult = requestHandler
// 						? requestHandler(cancellationSource.token)
// 						: starRequestHandler!(requestMessage.method, cancellationSource.token);
// 				} else if (Is.array(requestMessage.params) && (type === void 0 || type.numberOfParams > 1)) {
// 					handlerResult = requestHandler
// 						? requestHandler(...requestMessage.params, cancellationSource.token)
// 						: starRequestHandler!(requestMessage.method, ...requestMessage.params, cancellationSource.token);
// 				} else {
// 					handlerResult = requestHandler
// 						? requestHandler(requestMessage.params, cancellationSource.token)
// 						: starRequestHandler!(requestMessage.method, requestMessage.params, cancellationSource.token);
// 				}
// 				let promise = <Thenable<any | ResponseError<any>>>handlerResult;
// 				if (!handlerResult) {
// 					delete requestTokens[tokenKey];
// 					replySuccess(handlerResult, requestMessage.method, startTime);
// 				} else if (promise.then) {
// 					promise.then((resultOrError): any | ResponseError<any> => {
// 						delete requestTokens[tokenKey];
// 						reply(resultOrError, requestMessage.method, startTime);
// 					}, error => {
// 						delete requestTokens[tokenKey];
// 						if (error instanceof ResponseError) {
// 							replyError(<ResponseError<any>>error, requestMessage.method, startTime);
// 						} else if (error && Is.string(error.message)) {
// 							replyError(new ResponseError<void>(ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime);
// 						} else {
// 							replyError(new ResponseError<void>(ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime);
// 						}
// 					});
// 				} else {
// 					delete requestTokens[tokenKey];
// 					reply(handlerResult, requestMessage.method, startTime);
// 				}
// 			} catch (error) {
// 				delete requestTokens[tokenKey];
// 				if (error instanceof ResponseError) {
// 					reply(<ResponseError<any>>error, requestMessage.method, startTime);
// 				} else if (error && Is.string(error.message)) {
// 					replyError(new ResponseError<void>(ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime);
// 				} else {
// 					replyError(new ResponseError<void>(ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime);
// 				}
// 			}
// 		} else {
// 			replyError(new ResponseError<void>(ErrorCodes.MethodNotFound, `Unhandled method ${requestMessage.method}`), requestMessage.method, startTime);
// 		}
// 	}
// 	function handleResponse(responseMessage: ResponseMessage) {
// 		if (isDisposed()) {
// 			// See handle request.
// 			return;
// 		}
// 		if (responseMessage.id === null) {
// 			if (responseMessage.error) {
// 				logger.error(`Received response message without id: Error is: \n${JSON.stringify(responseMessage.error, undefined, 4)}`);
// 			} else {
// 				logger.error(`Received response message without id. No further error information provided.`);
// 			}
// 		} else {
// 			let key = String(responseMessage.id);
// 			let responsePromise = responsePromises[key];
// 			traceReceivedResponse(responseMessage, responsePromise);
// 			if (responsePromise) {
// 				delete responsePromises[key];
// 				try {
// 					if (responseMessage.error) {
// 						let error = responseMessage.error;
// 						responsePromise.reject(new ResponseError(error.code, error.message, error.data));
// 					} else if (responseMessage.result !== void 0) {
// 						responsePromise.resolve(responseMessage.result);
// 					} else {
// 						throw new Error('Should never happen.');
// 					}
// 				} catch (error) {
// 					if (error.message) {
// 						logger.error(`Response handler '${responsePromise.method}' failed with message: ${error.message}`);
// 					} else {
// 						logger.error(`Response handler '${responsePromise.method}' failed unexpectedly.`);
// 					}
// 				}
// 			}
// 		}
// 	}
// 	function handleNotification(message: NotificationMessage) {
// 		if (isDisposed()) {
// 			// See handle request.
// 			return;
// 		}
// 		let type: MessageType | undefined = undefined;
// 		let notificationHandler: GenericNotificationHandler | undefined;
// 		if (message.method === CancelNotification.type.method) {
// 			notificationHandler = (params: CancelParams) => {
// 				let id = params.id;
// 				let source = requestTokens[String(id)];
// 				if (source) {
// 					source.cancel();
// 				}
// 			}
// 		} else {
// 			let element = notificationHandlers[message.method];
// 			if (element) {
// 				notificationHandler = element.handler;
// 				type = element.type;
// 			}
// 		}
// 		if (notificationHandler || starNotificationHandler) {
// 			try {
// 				traceReceivedNotification(message);
// 				if (message.params === void 0 || (type !== void 0 && type.numberOfParams === 0)) {
// 					notificationHandler ? notificationHandler() : starNotificationHandler!(message.method);
// 				} else if (Is.array(message.params) && (type === void 0 || type.numberOfParams > 1)) {
// 					notificationHandler ? notificationHandler(...message.params) : starNotificationHandler!(message.method, ...message.params);
// 				} else {
// 					notificationHandler ? notificationHandler(message.params) : starNotificationHandler!(message.method, message.params);
// 				}
// 			} catch (error) {
// 				if (error.message) {
// 					logger.error(`Notification handler '${message.method}' failed with message: ${error.message}`);
// 				} else {
// 					logger.error(`Notification handler '${message.method}' failed unexpectedly.`);
// 				}
// 			}
// 		} else {
// 			unhandledNotificationEmitter.fire(message);
// 		}
// 	}
// 	function handleInvalidMessage(message: Message) {
// 		if (!message) {
// 			logger.error('Received empty message.');
// 			return;
// 		}
// 		logger.error(`Received message which is neither a response nor a notification message:\n${JSON.stringify(message, null, 4)}`);
// 		// Test whether we find an id to reject the promise
// 		let responseMessage: ResponseMessage = message as ResponseMessage;
// 		if (Is.string(responseMessage.id) || Is.number(responseMessage.id)) {
// 			let key = String(responseMessage.id);
// 			let responseHandler = responsePromises[key];
// 			if (responseHandler) {
// 				responseHandler.reject(new Error('The received response has neither a result nor an error property.'));
// 			}
// 		}
// 	}
// 	function traceSendingRequest(message: RequestMessage): void {
// 		if (trace === Trace.Off || !tracer) {
// 			return;
// 		}
// 		let data: string | undefined = undefined;
// 		if (trace === Trace.Verbose && message.params) {
// 			data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
// 		}
// 		tracer.log(`Sending request '${message.method} - (${message.id})'.`, data);
// 	}
// 	function traceSendNotification(message: NotificationMessage): void {
// 		if (trace === Trace.Off || !tracer) {
// 			return;
// 		}
// 		let data: string | undefined = undefined;
// 		if (trace === Trace.Verbose) {
// 			if (message.params) {
// 				data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
// 			} else {
// 				data = 'No parameters provided.\n\n';
// 			}
// 		}
// 		tracer.log(`Sending notification '${message.method}'.`, data);
// 	}
// 	function traceSendingResponse(message: ResponseMessage, method: string, startTime: number): void {
// 		if (trace === Trace.Off || !tracer) {
// 			return;
// 		}
// 		let data: string | undefined = undefined;
// 		if (trace === Trace.Verbose) {
// 			if (message.error && message.error.data) {
// 				data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`;
// 			} else {
// 				if (message.result) {
// 					data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`;
// 				} else if (message.error === void 0) {
// 					data = 'No result returned.\n\n';
// 				}
// 			}
// 		}
// 		tracer.log(`Sending response '${method} - (${message.id})'. Processing request took ${Date.now() - startTime}ms`, data)
// 	}
// 	function traceReceivedRequest(message: RequestMessage): void {
// 		if (trace === Trace.Off || !tracer) {
// 			return;
// 		}
// 		let data: string | undefined = undefined;
// 		if (trace === Trace.Verbose && message.params) {
// 			data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
// 		}
// 		tracer.log(`Received request '${message.method} - (${message.id})'.`, data);
// 	}
// 	function traceReceivedNotification(message: NotificationMessage): void {
// 		if (trace === Trace.Off || !tracer || message.method === LogTraceNotification.type.method) {
// 			return;
// 		}
// 		let data: string | undefined = undefined;
// 		if (trace === Trace.Verbose) {
// 			if (message.params) {
// 				data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`;
// 			} else {
// 				data = 'No parameters provided.\n\n';
// 			}
// 		}
// 		tracer.log(`Received notification '${message.method}'.`, data);
// 	}
// 	function traceReceivedResponse(message: ResponseMessage, responsePromise: ResponsePromise): void {
// 		if (trace === Trace.Off || !tracer) {
// 			return;
// 		}
// 		let data: string | undefined = undefined;
// 		if (trace === Trace.Verbose) {
// 			if (message.error && message.error.data) {
// 				data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`;
// 			} else {
// 				if (message.result) {
// 					data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`;
// 				} else if (message.error === void 0) {
// 					data = 'No result returned.\n\n';
// 				}
// 			}
// 		}
// 		if (responsePromise) {
// 			let error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : '';
// 			tracer.log(`Received response '${responsePromise.method} - (${message.id})' in ${Date.now() - responsePromise.timerStart}ms.${error}`, data);
// 		} else {
// 			tracer.log(`Received response ${message.id} without active response promise.`, data);
// 		}
// 	}
// 	function throwIfClosedOrDisposed() {
// 		if (isClosed()) {
// 			throw new ConnectionError(ConnectionErrors.Closed, 'Connection is closed.');
// 		}
// 		if (isDisposed()) {
// 			throw new ConnectionError(ConnectionErrors.Disposed, 'Connection is disposed.');
// 		}
// 	}
// 	function throwIfListening() {
// 		if (isListening()) {
// 			throw new ConnectionError(ConnectionErrors.AlreadyListening, 'Connection is already listening');
// 		}
// 	}
// 	function throwIfNotListening() {
// 		if (!isListening()) {
// 			throw new Error('Call listen() first.');
// 		}
// 	}
// 	function undefinedToNull(param: any) {
// 		if (param === void 0) {
// 			return null;
// 		} else {
// 			return param;
// 		}
// 	}
// 	function computeMessageParams(type: MessageType, params: any[]): any | any[] | null {
// 		let result: any | any[] | null;
// 		let numberOfParams = type.numberOfParams;
// 		switch (numberOfParams) {
// 			case 0:
// 				result = null;
// 				break;
// 			case 1:
// 				result = undefinedToNull(params[0]);
// 				break;
// 			default:
// 				result = [];
// 				for (let i = 0; i < params.length && i < numberOfParams; i++) {
// 					result.push(undefinedToNull(params[i]));
// 				}
// 				if (params.length < numberOfParams) {
// 					for (let i = params.length; i < numberOfParams; i++) {
// 						result.push(null);
// 					}
// 				}
// 				break;
// 		}
// 		return result;
// 	}
// 	let connection: MessageConnection = {
// 		sendNotification: (type: string | MessageType, ...params: any[]): void => {
// 			throwIfClosedOrDisposed();
// 			let method: string;
// 			let messageParams: any | any[] | null;
// 			if (Is.string(type)) {
// 				method = type;
// 				switch (params.length) {
// 					case 0:
// 						messageParams = null;
// 						break;
// 					case 1:
// 						messageParams = params[0];
// 						break;
// 					default:
// 						messageParams = params;
// 						break;
// 				}
// 			} else {
// 				method = type.method;
// 				messageParams = computeMessageParams(type, params);
// 			}
// 			let notificationMessage: NotificationMessage = {
// 				jsonrpc: version,
// 				method: method,
// 				params: messageParams
// 			}
// 			traceSendNotification(notificationMessage);
// 			messageWriter.write(notificationMessage);
// 		},
// 		onNotification: (type: string | MessageType | StarNotificationHandler, handler?: GenericNotificationHandler): void => {
// 			throwIfClosedOrDisposed();
// 			if (Is.func(type)) {
// 				starNotificationHandler = type as StarNotificationHandler;
// 			} else if (handler) {
// 				if (Is.string(type)) {
// 					notificationHandlers[type] = { type: undefined, handler }
// 				} else {
// 					notificationHandlers[type.method] = { type, handler };
// 				}
// 			}
// 		},
// 		sendRequest: <R, E>(type: string | MessageType, ...params: any[]) => {
// 			throwIfClosedOrDisposed();
// 			throwIfNotListening();
// 			let method: string;
// 			let messageParams: any | any[] | null;
// 			let token: CancellationToken | undefined = undefined;
// 			if (Is.string(type)) {
// 				method = type;
// 				switch (params.length) {
// 					case 0:
// 						messageParams = null;
// 						break;
// 					case 1:
// 						// The cancellation token is optional so it can also be undefined.
// 						if (CancellationToken.is(params[0])) {
// 							messageParams = null;
// 							token = params[0];
// 						} else {
// 							messageParams = undefinedToNull(params[0]);
// 						}
// 						break;
// 					default:
// 						const last = params.length - 1;
// 						if (CancellationToken.is(params[last])) {
// 							token = params[last];
// 							if (params.length === 2) {
// 								messageParams = undefinedToNull(params[0]);
// 							} else {
// 								messageParams = params.slice(0, last).map(value => undefinedToNull(value));
// 							}
// 						} else {
// 							messageParams = params.map(value => undefinedToNull(value));
// 						}
// 						break;
// 				}
// 			} else {
// 				method = type.method;
// 				messageParams = computeMessageParams(type, params);
// 				let numberOfParams = type.numberOfParams;
// 				token = CancellationToken.is(params[numberOfParams]) ? params[numberOfParams] : undefined;
// 			}
// 			let id = sequenceNumber++;
// 			let result = new Promise<R | ResponseError<E>>((resolve, reject) => {
// 				let requestMessage: RequestMessage = {
// 					jsonrpc: version,
// 					id: id,
// 					method: method,
// 					params: messageParams
// 				}
// 				let responsePromise: ResponsePromise | null = { method: method, timerStart: Date.now(), resolve, reject };
// 				traceSendingRequest(requestMessage);
// 				try {
// 					messageWriter.write(requestMessage);
// 				} catch (e) {
// 					// Writing the message failed. So we need to reject the promise.
// 					responsePromise.reject(new ResponseError<void>(ErrorCodes.MessageWriteError, e.message ? e.message : 'Unknown reason'));
// 					responsePromise = null;
// 				}
// 				if (responsePromise) {
// 					responsePromises[String(id)] = responsePromise;
// 				}
// 			});
// 			if (token) {
// 				token.onCancellationRequested(() => {
// 					connection.sendNotification(CancelNotification.type, { id });
// 				});
// 			}
// 			return result;
// 		},
// 		onRequest: <R, E>(type: string | MessageType | StarRequestHandler, handler?: GenericRequestHandler<R, E>): void => {
// 			throwIfClosedOrDisposed();
// 			if (Is.func(type)) {
// 				starRequestHandler = type as StarRequestHandler;
// 			} else if (handler) {
// 				if (Is.string(type)) {
// 					requestHandlers[type] = { type: undefined, handler };
// 				} else {
// 					requestHandlers[type.method] = { type, handler };
// 				}
// 			}
// 		},
// 		trace: (_value: Trace, _tracer: Tracer, sendNotification: boolean = false) => {
// 			trace = _value;
// 			if (trace === Trace.Off) {
// 				tracer = undefined;
// 			} else {
// 				tracer = _tracer;
// 			}
// 			if (sendNotification && !isClosed() && !isDisposed()) {
// 				connection.sendNotification(SetTraceNotification.type, { value: Trace.toString(_value) });
// 			}
// 		},
// 		onError: errorEmitter.event,
// 		onClose: closeEmitter.event,
// 		onUnhandledNotification: unhandledNotificationEmitter.event,
// 		onDispose: disposeEmitter.event,
// 		dispose: () => {
// 			if (isDisposed()) {
// 				return;
// 			}
// 			state = ConnectionState.Disposed;
// 			disposeEmitter.fire(undefined);
// 			let error = new Error('Connection got disposed.');
// 			Object.keys(responsePromises).forEach((key) => {
// 				responsePromises[key].reject(error);
// 			});
// 			responsePromises = Object.create(null);
// 			requestTokens = Object.create(null);
// 			messageQueue = new LinkedMap<string, Message>();
// 			// Test for backwards compatibility
// 			if (Is.func(messageWriter.dispose)) {
// 				messageWriter.dispose();
// 			}
// 			if (Is.func(messageReader.dispose)) {
// 				messageReader.dispose();
// 			}
// 		},
// 		listen: () => {
// 			throwIfClosedOrDisposed();
// 			throwIfListening();
// 			state = ConnectionState.Listening;
// 			messageReader.listen(callback);
// 		},
// 		inspect: (): void => {
// 			console.log("inspect");
// 		}
// 	};
// 	connection.onNotification(LogTraceNotification.type, (params) => {
// 		if (trace === Trace.Off || !tracer) {
// 			return;
// 		}
// 		tracer.log(params.message, trace === Trace.Verbose ? params.verbose : undefined);
// 	});
// 	return connection;
// }
// function isMessageReader(value: any): value is MessageReader {
// 	return value.listen !== void 0 && value.read === void 0;
// }
// function isMessageWriter(value: any): value is MessageWriter {
// 	return value.write !== void 0 && value.end === void 0;
// }
// export function createMessageConnection(reader: MessageReader, writer: MessageWriter, logger?: Logger, strategy?: ConnectionStrategy): MessageConnection;
// export function createMessageConnection(inputStream: NodeJS.ReadableStream, outputStream: NodeJS.WritableStream, logger?: Logger, strategy?: ConnectionStrategy): MessageConnection;
// export function createMessageConnection(input: MessageReader | NodeJS.ReadableStream, output: MessageWriter | NodeJS.WritableStream, logger?: Logger, strategy?: ConnectionStrategy): MessageConnection {
// 	if (!logger) {
// 		logger = NullLogger;
// 	}
// 	let reader = isMessageReader(input) ? input : new StreamMessageReader(input);
// 	let writer = isMessageWriter(output) ? output : new StreamMessageWriter(output);
// 	return _createMessageConnection(reader, writer, logger, strategy);
// }
